package org.apache.solr.client;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.solr.client.util.ParamNames;


public class SolrQuery 
{
	public enum ORDER {
		desc,
		asc;
	}
	
	public static final String VERSION = "2.2";
	
	private String _query;
	private Integer _start;
	private Integer _rows;
	private boolean _showDebugInfo = false;
	private List<String> _fields = null;
	private boolean _includeScore = false;
	private List<SortField> _sort = null;
	private FacetParams _facet = new FacetParams();
	
	public String getQueryString() throws UnsupportedEncodingException
	{
		StringBuilder builder = new StringBuilder();
		if( _query == null ) {
			throw new RuntimeException( "can't have a null query!" );
		}
		builder.append( ParamNames.Q ).append( '=' ).append( URLEncoder.encode( _query.trim(), "UTF-8" ) );
		if( _sort != null ) {
			builder.append( ';' );
			Iterator<SortField> iter = _sort.iterator();
			while( iter.hasNext() ) {
				SortField f = iter.next();
				builder.append( f.field ).append( '+').append( f.order );
				if( iter.hasNext() ) {
					builder.append( ", " );
				}
			}
		}
		
		if( _start != null ) {
			builder.append( '&' ).append( ParamNames.START ).append( '=' ).append( _start );
		}
		if( _rows != null ) {
			builder.append( '&' ).append( ParamNames.ROWS ).append( '=' ).append( _rows );
		}
		
		if( _fields != null && _fields.size() > 0 ) {
			builder.append( '&' ).append( ParamNames.FL ).append( '=' );
			for( String f : _fields ) {
				builder.append( f ).append( ',' );
			}
			if( _includeScore ) {
				builder.append( "score" );
			}
		}
		else if( _includeScore ) {
			builder.append( '&' ).append( ParamNames.FL ).append( "=*,score" );
		}
		
		if( _facet.isEnabled() ) {
			builder.append( '&' ).append( ParamNames.FACET ).append( "=true" );
			for( String f : _facet.field ) {
				builder.append( '&' ).append( ParamNames.FACET_FIELD ).append( "=" ).append( f );
			}
			builder.append( '&' ).append( ParamNames.FACET_LIMIT ).append( "=" ).append( _facet.limit );
			
			// defauls ok, but lets set them explicitly...
			builder.append( '&' ).append( ParamNames.FACET_ZEROS ).append( "=" ).append( _facet.zeros );
			builder.append( '&' ).append( ParamNames.FACET_MISSING ).append( "=" ).append( _facet.missing );
		}
		
		// Version
		builder.append( '&' ).append( ParamNames.VERSION ).append( '=' ).append( VERSION );
		
		// debug
		if( _showDebugInfo ) {
			builder.append( '&' ).append( ParamNames.DEBUG_QUERY ).append( "=true" );
		}		
		return builder.toString();
	}
	
	@Override
	public String toString()
	{
		try {
			return getQueryString();
		}
		catch (Exception ex) {}
		return super.toString();
	}
	
	//-----------------------------------------------------------------
	//-----------------------------------------------------------------

	private static final class SortField {
		public final String field;
		public final ORDER order;
		
		public SortField( String f, ORDER o )
		{
			field = f;
			order = o;
		}
	}
	
	public static class FacetParams {
		public List<String> field = new ArrayList<String>(3);
		public int limit = 25;
		public boolean zeros   = false;
		public boolean missing = false;
		
		public boolean isEnabled()
		{
			return field.size() > 0;
		}
	}

	//-----------------------------------------------------------------
	//-----------------------------------------------------------------
	
	public void addFacetField( String f )
	{
		_facet.field.add( f );
	}
	
	public void setFacetLimit( int lim )
	{
		_facet.limit = lim;
	}
	
	public void addSortField( String field, ORDER order )
	{
		if( _sort == null ) {
			_sort = new ArrayList<SortField>( 2 );
		}
		_sort.add( new SortField( field, order ) );
	}

	public void setFields(List<String> fields) {
		_fields = fields;
	}

	public void setIncludeScore(boolean includeScore) {
		_includeScore = includeScore;
	}

	public void setQuery(String query) {
		_query = query;
	}

	public void setRows(Integer rows) {
		_rows = rows;
	}

	public void setShowDebugInfo(boolean showDebugInfo) {
		_showDebugInfo = showDebugInfo;
	}

	public void setSort(List<SortField> sort) {
		_sort = sort;
	}

	public void setStart(Integer start) {
		_start = start;
	}
}
